package models

import (
	"context"
	"errors"
	"fmt"
	"github.com/zeromicro/go-zero/core/stores/cache"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"strings"
)

//var _ UserExtendModel = (*customUserExtendModel)(nil)
//
//type (
//	UserExtendModel interface {
//		userModel
//	}
//
//	customUserExtendModel struct {
//		*defaultUserModel
//	}
//)
//
//func NewUserExtendModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) UserExtendModel {
//	return &customUserExtendModel{
//		defaultUserModel: newUserModel(conn, c, opts...),
//	}
//}

type UserExtendModel interface {
	FindOneByMobile(ctx context.Context, mobile string, status int64) (*User, error)
	FindOneByEmail(ctx context.Context, email string, status int64) (*User, error)
	CheckPassword(ctx context.Context, id int64, password string) error
	FindListByPage(ctx context.Context, name, mobile, email, orderBy string, status, lastId, limit int64) ([]*User, int64, error)
	FindListByIDs(ctx context.Context, ids []int64) ([]*User, int64, error)
}

func NewUserExtendModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) UserExtendModel {
	return &customUserModel{
		defaultUserModel: newUserModel(conn, c, opts...),
	}
}

func (m *defaultUserModel) FindOneByMobile(ctx context.Context, mobile string, status int64) (*User, error) {
	var user User
	query := fmt.Sprintf("select %s from %s where mobile = ? ", userRows, m.table)
	if status != 0 {
		query += fmt.Sprintf(" and status = %d", status)
	}
	query += " limit 1"
	err := m.QueryRowNoCacheCtx(ctx, &user, query, mobile)
	if err != nil {
		return nil, err
	}
	return &user, nil
}

func (m *defaultUserModel) FindOneByEmail(ctx context.Context, email string, status int64) (*User, error) {
	var user User
	query := fmt.Sprintf("select %s from %s where email = ? ", userRows, m.table)
	if status != 0 {
		query += fmt.Sprintf(" and status = %d", status)
	}
	query += " limit 1"
	err := m.QueryRowNoCacheCtx(ctx, &user, query, email)
	if err != nil {
		return nil, err
	}
	return &user, nil
}

func (m *defaultUserModel) CheckPassword(ctx context.Context, id int64, password string) error {
	user, err := m.FindOne(ctx, id)
	if err != nil {
		return err
	}

	if user.Password != password {
		return errors.New("password not match")
	}
	return nil
}

func (m *defaultUserModel) FindListByPage(ctx context.Context, name, mobile, email, orderBy string, status, lastId, limit int64) ([]*User, int64, error) {
	var (
		count int64
		users []*User
	)
	// SQL基础部分，使用占位符(?)代替直接拼接
	countQuery := fmt.Sprintf("select count(*) from %s where 1 = 1 ", m.table)
	listQuery := fmt.Sprintf("select %s from %s where 1 = 1 ", userRows, m.table)
	countArgs := make([]interface{}, 0) // 存储参数值，用于参数化查询
	listArgs := make([]interface{}, 0)  // 存储参数值，用于参数化查询

	// 处理name模糊查询
	if name != "" {
		countQuery += " and name like ?"
		listQuery += " and name like ?"
		countArgs = append(countArgs, "%"+name+"%") // 占位符对应的值
		listArgs = append(listArgs, "%"+name+"%")   // 占位符对应的值
	}

	// 处理mobile模糊查询
	if mobile != "" {
		countQuery += " and mobile like ?"
		listQuery += " and mobile like ?"
		countArgs = append(countArgs, "%"+mobile+"%")
		listArgs = append(listArgs, "%"+mobile+"%")
	}

	// 处理email模糊查询
	if email != "" {
		countQuery += " and email like ?"
		listQuery += " and email like ?"
		countArgs = append(countArgs, "%"+email+"%")
		listArgs = append(listArgs, "%"+email+"%")
	}

	// 处理status精确查询
	if status != 0 {
		countQuery += " and status like ?"
		listQuery += " and status like ?"
		countArgs = append(countArgs, status)
		listArgs = append(listArgs, status)
	}

	err := m.QueryRowNoCacheCtx(ctx, &count, countQuery, countArgs...)
	if err != nil {
		return nil, 0, err
	}

	// 处理limit（校验合法性，默认限制最大条数）
	if limit <= 0 || limit > 1000 { // 假设业务最大允许1000条
		limit = 20 // 默认值
	}
	// 处理分页条件（仅当lastId > 0时添加，增强灵活性）
	switch orderBy {
	case "asc":
		listQuery += " and id > ? order by id asc limit ?"
	case "desc":
		listQuery += " and id < ? order by id desc limit ?"
	}
	listArgs = append(listArgs, lastId, limit)
	// 使用参数化查询，将args传入，避免SQL注入
	err = m.QueryRowsNoCacheCtx(ctx, &users, listQuery, listArgs...)
	if err != nil {
		return nil, count, err
	}
	return users, count, nil
}

func (m *defaultUserModel) FindListByIDs(ctx context.Context, ids []int64) ([]*User, int64, error) {
	var (
		count        int64
		users        []*User
		placeholders []string
		args         []interface{}
	)
	if len(ids) == 0 {
		return users, count, nil
	}

	for _, id := range ids {
		placeholders = append(placeholders, "?")
		args = append(args, id)
	}
	query := fmt.Sprintf("select %s from %s where id in (%s) ", userRows, m.table, strings.Join(placeholders, ","))
	err := m.QueryRowsNoCacheCtx(ctx, &users, query, args...)
	if err != nil {
		return nil, 0, err
	}

	count = int64(len(users))
	return users, count, nil
}
